/*
 * DesktopPaneWM.java
 *
 * Created on March 20, 2007, 12:25 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.glossitope.container.wm;

import com.sun.jna.examples.WindowUtils;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.util.HashMap;

import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.glossitope.container.Core;

import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.timing.TimingTarget;
import org.jdesktop.animation.timing.interpolation.PropertySetter;

import org.glossitope.container.CustomDesktopPane;
import org.glossitope.container.DesktopBackground;
import org.glossitope.container.Environment;
import org.glossitope.container.MainPanel;
import org.glossitope.desklet.DeskletContainer;
import org.glossitope.container.security.DefaultContext;
import org.glossitope.container.security.DeskletConfig;
import org.glossitope.container.security.InternalDialogContainer;
import org.glossitope.container.security.InternalFrameContainer;
import org.glossitope.container.security.permissions.GPerm;
import org.glossitope.container.security.permissions.PermissionsDialog;
import org.glossitope.container.security.permissions.SecurityStorage;
import org.glossitope.container.util.GlobalMouse;
import org.glossitope.container.util.MoveMouseListener;
import org.glossitope.desklet.services.PermissionRequest;
import org.joshy.util.u;

/**
 *
 * @author joshy
 */
public class DesktopPaneWM extends WindowManager {
    
    private HashMap<JPanel, JInternalFrame> iframes = new HashMap<JPanel, JInternalFrame>();
    public JDesktopPane desktop;
    private JFrame frame;
    private GlobalMouse globalMouseService = GlobalMouse.getInstance();
    

    private JComponent dock;
    private Core core;
    
    /** Creates a new instance of DesktopPaneWM */
    public DesktopPaneWM(Core core) {
        this.core = core;
        this.desktop = new CustomDesktopPane();
        
        
        frame = new JFrame("Glossitope (desktop mode)");
        u.p("show title bar = " + Environment.showFrameTitleBar);
        if(!Environment.showFrameTitleBar) {
            //frame.setUndecorated(true);
        }
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(desktop,"Center");
        JInternalFrame jif = new JInternalFrame("title");
        
        desktop.add(jif);
        jif.setVisible(true);
        jif.repaint();
        frame.pack();
    }
    
    
    /* ===== the desklet container lifecycle ======= */
    
    public DeskletContainer createInternalContainer(final DefaultContext context) {
        context.services.put(org.glossitope.desklet.services.GlobalMouse.class, globalMouseService);
        context.services.put(PermissionRequest.class, new PermissionRequest() {

            public boolean isAlreadyApproved(String permissionType, Object[] parameters, String description) {
                SecurityStorage ss = SecurityStorage.getInstance();
                String uuid = context.getConfig().getUUID();
                return ss.isGranted(uuid, permissionType, parameters);
            }

            public boolean requestPermission(String permissionType, Object[] parameters, String description) {
                DeskletConfig cfg = context.getConfig();
                StringBuffer params = new StringBuffer();
                for(Object o : parameters) {
                    params.append(""+o);
                    params.append(", ");
                }
                int approved = PermissionsDialog.showConfirmDialog(core.mainPanel, cfg.getName(), 
                        permissionType + ":" + params.toString(), description);
                if(approved == JOptionPane.YES_OPTION) {
                    GPerm gperm = new GPerm();
                    gperm.setPermType(permissionType);
                    gperm.setValue((String)parameters[0]);
                    gperm.setCode(context.getConfig().getUUID());
                    gperm.setType(GPerm.Type.ALLOW_PERM);
                    SecurityStorage.getInstance().grantPermissionPermanently(context.getConfig().getUUID(), gperm);
                    return true;
                }
                
                return false;
            }
        });
        
        final DesktopIFC ifc = new DesktopIFC(context.getConfig().getName(),this, context);
        iframes.put(ifc.panel, ifc.iframe);
        return ifc;
    }


    @Override
    public void convertInternalToExternalContainer(DeskletContainer dc) {
        System.out.println("converting an internal to an external");
        DesktopIFC ifc = (DesktopPaneWM.DesktopIFC) dc;
        iframes.remove(ifc.panel);
        desktop.remove(ifc.iframe);
        ifc.switchToHeavy();
    }

    @Override
    public void convertExternalToInternalContainer(DeskletContainer dc) {
        u.p("converting an external to an internal");
        DesktopIFC ifc = (DesktopPaneWM.DesktopIFC) dc;
        iframes.put(ifc.panel, ifc.iframe);
        ifc.switchToLight();
        desktop.add(ifc.iframe);
        if(!ifc.isVisible()) {
            ifc.pack();
            ifc.setVisible(true);
        }
        ifc.iframe.repaint();
        desktop.repaint();
    }

    
    public void showContainer(DeskletContainer dc) {
        final InternalFrameContainer ifc = (InternalFrameContainer) dc;
        desktop.add(ifc.iframe);
        if(!ifc.isVisible()) {
            ifc.pack();
            ifc.setVisible(true);
        }
    }
    

    private class DesktopIFC extends InternalFrameContainer {
        DefaultContext context;
        private JFrame jframe;
        boolean isHeavy = false;
        DesktopIFC(String title, WindowManager wm, DefaultContext context) {
            super(title,wm);
            this.context = context;
        }

        @Override
        public Point2D getLocation() {
            //System.out.println("my current location = " + super.getLocation());
            return super.getLocation();
        }

        @Override
        public void setLocation(Point2D location) {
            //System.out.println("set location");
            if(isHeavy) {
                jframe.setLocation((int)location.getX(),(int)location.getY());
            } else {
                super.setLocation(location);
            }
        }
        
        public void switchToHeavy() {
            jframe = new JFrame(context.getConfig().getName());
            if(Environment.useShapedToplevelWindows) {
                jframe.setUndecorated(true);
            }
            jframe.setAlwaysOnTop(true);
            jframe.setResizable(isResizable());
            iframe.remove(panel);
            jframe.add(panel);
            jframe.pack();
            jframe.setSize(iframe.getSize());
            jframe.setLocation(0,iframe.getY());
            if(Environment.useShapedToplevelWindows) {
                u.p("alpha supported = " +WindowUtils.isWindowAlphaSupported());
                WindowUtils.setWindowMask(jframe, context.getContainer().getShape());
            }
            
            jframe.setVisible(true);
            isHeavy = true;
        }
        public void switchToLight() {
            jframe.remove(panel);
            iframe.setContentPane(panel);
            iframe.pack();
            iframe.setSize(jframe.getSize());
            iframe.setLocation(0,jframe.getY());
            iframe.setVisible(true);

            jframe.setVisible(false);
            jframe.dispose();
            jframe = null;
            isHeavy = false;
        }
        
        public MoveMouseListener createMoveMouseListener(WindowManager wm) {
            //u.p("creating a move mouse listener");
            return new MoveMouseListener(this,wm) {

                public void mouseDragged(MouseEvent e) {
                    super.mouseDragged(e);
                    int x = e.getPoint().x;
                    int y = e.getPoint().y;
                    if(isHeavy) {
                        //u.p("heavy dragging:" + e.getPoint());
                        x+=jframe.getX();
                        y+=jframe.getY();
                        //u.p("final = " + x + " , " + y);
                        if(x > 1500) {
                            if(core.getCloser().isWindowClosed()) {
                                core.getCollapseWindowAction().doExpand();
                                convertExternalToInternalContainer(DesktopIFC.this);
                            }
                        }
                    } else {
                        //u.p("dragging: " + e.getPoint());
                        //u.p("panel = " + panel);
                        //u.p("frame = " + iframe);
                        x+=iframe.getX();
                        y+=iframe.getY();
                        //u.p("converted = " + SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), iframe));
                        //u.p("final = " + x + " , " + y);
                        if(x < 0) {
                            //u.p("out of the screen");
                            if(!core.getCloser().isWindowClosed()) {
                                core.getCollapseWindowAction().doCollapse();
                                convertInternalToExternalContainer(DesktopIFC.this);
                            }
                        }
                    }
                }
                protected Point2D getScreenLocation() {
                    if(isHeavy) {
                        return jframe.getLocation();
                    }
                    return super.getScreenLocation();
                }
                protected Point getScreenLocation(MouseEvent e) {
                    if(isHeavy) {
                        Point cursor = e.getPoint();
                        Point2D target_location = jframe.getLocation();
                        return new Point(
                            (int)(target_location.getX()+cursor.getX()),
                            (int)(target_location.getY()+cursor.getY()));
                    } else {
                        return super.getScreenLocation(e);
                    }
                }
            };
        };
    }

    
    public void destroyContainer(DeskletContainer dc) {
        Dimension dim = getContainerSize();
        final InternalFrameContainer ifc = (InternalFrameContainer) dc;
        Animator an = PropertySetter.createAnimator(500, ifc.iframe,
                "location", ifc.iframe.getLocation(),
                new Point(-dim.width, dim.height));
        
        an.addTarget(new TimingTarget() {
            public void begin() {          }
            public void end() {
                //wm.removeDesklet(ifc.iframe);
                desktop.remove(ifc.iframe);
                iframes.remove(ifc.panel);
            }
            public void repeat() {    }
            public void timingEvent(float fraction) {        }
        });
        
        an.start();
    }
    
    /*
    public void setLocation(DeskletContainer ifc, Point2D point) {
        ((InternalFrameContainer)ifc).iframe.setLocation(GraphicsUtil.toPoint(point));
    }
    
    public Point2D getLocation(DeskletContainer deskletContainer) {
        final InternalFrameContainer ifc = (InternalFrameContainer) deskletContainer;
        Point location = ifc.iframe.getLocation();
        return location;
    }*/

    public void setDesktopBackground(DesktopBackground bg) {
        ((CustomDesktopPane)desktop).setDesktopBackground(bg);
    }

    public Dimension getContainerSize() {
        return desktop.getSize();
    }

    public Object getTopLevel() {
        return frame;
    }

    public void setDockComponent(JComponent dock) {
        this.dock = dock;
        frame.getContentPane().removeAll();
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(desktop,"Center");
        frame.getContentPane().add(dock,"West");
        frame.getContentPane().validate();
    }

    public void setDockingSide(MainPanel.DockingSide side) {
        if(dock == null) return;
        frame.remove(dock);
        if(side == MainPanel.DockingSide.Left) {
            frame.getContentPane().add(dock,"East");
        }
        if(side == MainPanel.DockingSide.Right) {
            frame.getContentPane().add(dock,"West");
        }
        frame.getContentPane().validate();
        dock.validate();
    }

    public DeskletContainer createDialog(DeskletContainer deskletContainer) {
        InternalFrameContainer ifc = (InternalFrameContainer) deskletContainer;
        InternalDialogContainer cont = new InternalDialogContainer("Configuration", this , ifc);
        desktop.add(cont.dialog);
        return cont;
    }

    public DeskletContainer createExternalContainer(DefaultContext context) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    
}
